package com.zyj.benchmark.sample;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.openjdk.jmh.runner.options.TimeValue;

import java.util.concurrent.TimeUnit;

/**
 * 当我们的benchmark是测量多线程的执行效率的时候,
 * 有一个问题, 不能被忽视
 * 比如我们设置一个benchmark同时并发100个线程执行, 我们的100个线程怎么初始化,
 * 是全部初始化完成之后, 再执行呢?
 * 还是每个线程初始化好了就直接执行?
 * ---
 * 如果选择每个线程各自初始化好了就立刻执行benchmark, 会导致CPU使用率不断变化, 给JMH带来很多的不确定性; 比如先初始化的一直占用时间片后面的线程初始化不了
 * 所以最好的策略是, 所有线程都初始化之后, 再一起执行benchmark; (这也是默认的策略)
 * 这里就有一个参数去控制
 * .syncIterations(true)
 * ---
 * 这种做法其实也是有实际意义的
 * 比如现在双十一, 我们的订单服务突然会处理大量的请求
 * 这时候刚刚动态扩容的机器肯定是
 */
@State(Scope.Thread)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
public class Sample_17_SyncIterations {

    private double src;

    @Benchmark
    public double test() { //单纯为了演示的耗时方法, 没有特殊意义
        double s = src;
        for (int i = 0; i < 1000; i++) {
            s = Math.sin(s);
        }
        return s;
    }

    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(Sample_17_SyncIterations.class.getSimpleName())
                .warmupTime(TimeValue.seconds(1))
                .warmupIterations(1)
                .measurementTime(TimeValue.seconds(1))
                .measurementIterations(1)
                .threads(Runtime.getRuntime().availableProcessors() * 16) //设置 处理器核心数*16个 线程同时执行
//                .threads(1)
                .forks(1)
                .syncIterations(true) //不设置的话, 默认是true
                // Should JMH synchronize iterations? This would significantly
                // lower the noise in multithreaded tests, by making
                // sure the measured part happens only when all workers
                // are running. (default: true)
                .build();

        new Runner(opt).run();
    }
}
